package priv.lhy.activity.services.processor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import priv.lhy.activity.dal.entity.ActDrawAward;
import priv.lhy.activity.dal.entity.ActDrawAwardItem;
import priv.lhy.activity.dal.persistence.ActDrawAwardMapper;
import priv.lhy.activity.services.processor.constants.DrawContants;
import priv.lhy.activity.services.processor.exception.RewardException;
import priv.lhy.activity.services.processor.exception.UnrewardException;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * author : lihy
 * date : 2019/2/16 10:10
 */
@Service("activityTurntableDrawProxy")
public class ActivityTurntableDrawProxy implements ApplicationContextAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(ActivityTurntableDrawProxy.class);

    //放大倍数
    private static final int MULRIPLE = 1000;

    //针对不同奖品类型的处理器
    Map<Integer, IRewardProcessor> rewardProcessorMap = new ConcurrentHashMap<>();

    @Autowired
    private ActDrawAwardMapper actDrawAwardMapper;

    @Autowired
    RedisTemplate redisTemplate;

    public ActivityDrawContext doDrawForProxy(ActivityDrawContext context) {
        //TODO 检测当前用户剩余抽奖次数
        try {
            List<ActDrawAwardItem> awardItems = (List<ActDrawAwardItem>) redisTemplate.opsForValue().get(DrawContants.DRAW_ITEM);

            ActDrawAwardItem item = doPlay(awardItems);

            ActDrawAward actDrawAward = actDrawAwardMapper.queryAwardById(item.getAwardId());

            context.setActDrawAwardItem(item);

            //奖品的子域
            rewardProcessorMap.get(actDrawAward.getAwardType()).doReword(context);
        } catch (UnrewardException e) {
            LOGGER.info("未抽到奖品或出现异常情况");
        } finally {
            LOGGER.info("ActivityTurntableDrawProxy.doDrawForProxy->{} ", context);
        }
        return context;
    }

    /**
     * 抽奖
     *
     * @param awardItems
     * @return
     */
    private ActDrawAwardItem doPlay(List<ActDrawAwardItem> awardItems) {
        ActDrawAwardItem awardItem = null;
        if (awardItems.isEmpty()) {
            throw new RewardException("奖项未设定或未正确初始化");
        }
        int lastScope = 0;
        //打乱顺序
        Collections.shuffle(awardItems);

        Map<Integer, int[]> awardItemScope = new HashMap<>();
        for (ActDrawAwardItem item : awardItems) {
            int currentScope = lastScope + new BigDecimal(item.getProbability()).multiply(new BigDecimal(MULRIPLE)).intValue();
            awardItemScope.put(item.getId(), new int[]{lastScope + 1, currentScope});
            lastScope = currentScope;
        }
        int luckyNumber = new Random().nextInt(MULRIPLE);
        int luckyPrizeId = 0;
        if (!awardItemScope.isEmpty()) {
            Set<Map.Entry<Integer, int[]>> set = awardItemScope.entrySet();
            for (Map.Entry<Integer, int[]> entry : set) {
                if (luckyNumber >= entry.getValue()[0] && luckyNumber <= entry.getValue()[1]) {
                    luckyPrizeId = entry.getKey();
                    break;
                }
            }
        }
        for (ActDrawAwardItem item : awardItems) {
            if (item.getId() == luckyPrizeId) {
                awardItem = item;
                break;
            }
        }

        return awardItem;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        rewardProcessorMap.put(DrawContants.award_type_enum.FINANCE.getValue(),
                (IRewardProcessor) applicationContext
                        .getBean("financeRewardProcessor"));
        rewardProcessorMap.put(DrawContants.award_type_enum.JD_CARD.getValue(),
                (IRewardProcessor) applicationContext
                        .getBean("jdCardRewardProcessor"));
        rewardProcessorMap.put(DrawContants.award_type_enum.NONE.getValue(),
                (IRewardProcessor) applicationContext
                        .getBean("noneRewardProcessor"));
    }
}
